package com.lpb.spring.lpbspring.aop.proxy.weaving;

import com.google.common.collect.Lists;
import com.lpb.spring.lpbspring.aop.advisor.Advisor;
import com.lpb.spring.lpbspring.aop.advisor.PointcutAdvisor;
import com.lpb.spring.lpbspring.ioc.BeanFactory;
import org.apache.commons.collections.CollectionUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author linpengbo
 * @date 2022/12/9
 */
public class AopProxyWeaving {


    /**
     * 代理功能的织入
     *
     * @param target
     * @param method
     * @param advisorList
     * @param beanFactory
     * @return
     */
    public static Object applyAdvisor(Object target, Method method, Object[] args, List<Advisor> advisorList, BeanFactory beanFactory) throws Exception {
        List<Object> adviceList = getAdviceList(target.getClass(), method, advisorList, beanFactory);
        if (CollectionUtils.isEmpty(adviceList)) {
            return method.invoke(target, args);
        }
        AopAdviceWeavingChain chain=new AopAdviceWeavingChain(target,method,args,adviceList,beanFactory);
        return chain.invoke();
    }

    private static List<Object> getAdviceList(Class<?> clazz, Method method, List<Advisor> advisorList, BeanFactory beanFactory) throws Exception {
        if (CollectionUtils.isEmpty(advisorList)) {
            return Lists.newArrayList();
        }
        List<Object> adviceList = Lists.newArrayList();
        for (Advisor advisor : advisorList) {
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pa = (PointcutAdvisor) advisor;
                if (pa.getPointcut().matchMethod(clazz, method)) {
                    String adviceBeanName = advisor.getAdviceBeanName();
                    adviceList.add(beanFactory.getBean(adviceBeanName));
                }
            }
        }
        return adviceList;
    }
}
